﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Chat
{
    public class IllegalCmdExEventArgs : EventArgs
    {
        public IllegalCmdException IllegalCommandException { get; protected set; }
        public bool Terminate { set; get; }
        public IllegalCmdExEventArgs(IllegalCmdException illegalCommandException)
        {
            IllegalCommandException = illegalCommandException;
            Terminate = false;
        }
    }

    public class DisconnectedExEventArgs : EventArgs
    {
        public Exception DisconnectedException { get; protected set; }
        public DisconnectedExEventArgs(Exception disconnectedException)
        {
            DisconnectedException = disconnectedException;
        }
    }

    public class CmdProcessorThread<InCmd> where InCmd : Command
    {
        protected Thread ProcessorTh { get; set; }
        protected CmdProcessor<InCmd> CommandProcessor { get; set; }
        protected ICmdReceiver<InCmd> Receiver { get; set; }

        // protected Connection<InCmd> Connection { get; set; }
        // protected CmdSerializer<InCmd> Serializer { get; set; }

        protected bool Terminated { get; set; }
        
        public event EventHandler<IllegalCmdExEventArgs> IllegalCmdReceived;
        public event EventHandler<DisconnectedExEventArgs> Disconnected;

        public CmdProcessorThread(
            CmdProcessor<InCmd> cmdProcssr,
            ICmdReceiver<InCmd> receiver)
        {
            CommandProcessor = cmdProcssr;
            Receiver = receiver;

            ProcessorTh = new Thread(CmdProcessorThreadMain);
            ProcessorTh.IsBackground = true;
            Terminated = false;
        }

        public void Start()
        {
            ProcessorTh.Start();
        }

        public void Stop()
        {
            if (Thread.CurrentThread.ManagedThreadId != ProcessorTh.ManagedThreadId)
            {
                if (ProcessorTh.IsAlive)
                    ProcessorTh.Abort();
            }
        }

        protected void CmdProcessorThreadMain()
        {
            try
            {
                ProcessCommands();
            }
            catch (ThreadAbortException)
            {
            }
            finally
            {
                Terminated = true;
            }
        }

        protected void ProcessCommands()
        {
            while (!Terminated)
            {
                try
                {
                    while (true)
                    {
                        CommandProcessor.ProcessCommand(Receiver);
                    }
                }
                catch (IllegalCmdException ex)
                {
                    IllegalCmdExEventArgs evtArgs = new IllegalCmdExEventArgs(ex);
                    OnIllegalCmdException(evtArgs);

                    if (evtArgs.Terminate)
                        Terminated = true;
                }
                catch (Exception ex)
                {
                    OnDisconnected(new DisconnectedExEventArgs(ex));
                    Terminated = true;
                }
            }
        }

        private void OnDisconnected(DisconnectedExEventArgs disconnectedExEventArgs)
        {
            if (Disconnected != null)
                Disconnected(this, disconnectedExEventArgs);
        }

        private void OnIllegalCmdException(IllegalCmdExEventArgs illegalCmdExEventArgs)
        {
            if (IllegalCmdReceived != null)
                IllegalCmdReceived(this, illegalCmdExEventArgs);
        }
    }
}
